﻿using EventHandlerDemo.Domain.Bases;
using EventHandlerDemo.Domain.OrderAttachments;
using EventHandlerDemo.Domain.OrderEventLogs;
using EventHandlerDemo.Domain.Orders;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace EventHandlerDemo.Infrastructure.EFCore;

public class AppDbContext : DbContext
{
    private readonly IPublisher _publisher;

    public AppDbContext(DbContextOptions<AppDbContext> options, IPublisher publisher) : base(options)
    {
        _publisher = publisher;
    }

    public DbSet<Order> Orders { get; set; }
    public DbSet<OrderEventLog> OrderEventLogs { get; set; }
    public DbSet<OrderAttachment> OrderAttachments { get; set; }

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        var entityChangeReport = new EntityChangeReport();

        foreach (var entry in ChangeTracker.Entries().ToList())
        {
            var generatesDomainEventsEntity = entry.Entity as IGeneratesDomainEvents;
            if (generatesDomainEventsEntity == null)
            {
                continue;
            }

            if (generatesDomainEventsEntity.DomainEvents == null || generatesDomainEventsEntity.DomainEvents.Count <= 0)
            {
                continue;
            }

            entityChangeReport.DomainEvents.AddRange(generatesDomainEventsEntity.DomainEvents.Select(eventData => new DomainEventEntry(entry, eventData)));
            generatesDomainEventsEntity.DomainEvents.Clear();
        }

        var result = await base.SaveChangesAsync(cancellationToken);

        foreach (var domainEvent in entityChangeReport.DomainEvents)
        {
            await _publisher.Publish(domainEvent.EventData, cancellationToken);
        }

        return result;
    }
}
